﻿using System;
using System.Collections.Generic;
using System.Data.Entity.Migrations;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WikeSoft.WorkFlowEngine.Entities;
using WikeSoft.WorkFlowEngine.Enum;
using WikeSoft.WorkFlowEngine.Extension;
using WikeSoft.WorkFlowEngine.Filter;
using WikeSoft.WorkFlowEngine.Interfaces;
using WikeSoft.WorkFlowEngine.Models;
using WikeSoft.WorkFlowEngine.Tools;

namespace WikeSoft.WorkFlowEngine.AppServices
{
    /// <summary>
    /// 流程定义
    /// </summary>
    public class WorkFlowDesignService : IWorkFlowDesignService
    {

        /// <summary>
        /// 添加流程定义
        /// </summary>
        /// <param name="flowDef"></param>
        /// <returns>返回流程定义Id,flowDefId</returns>
        public string AddFlowDef(Models.WorkFlowDefinition flowDef)
        {
            using (var context = new WorkFlowDbContext())
            {
                if (String.IsNullOrEmpty(flowDef.Id))
                    flowDef.Id = Guid.NewGuid().ToString().ToUpper();
                Entities.WorkFlowDef data = new Entities.WorkFlowDef()
                {
                    Id = flowDef.Id,
                    WorkFlowDefKey = flowDef.FlowDefKey,
                    WorkFlowDefName = flowDef.FlowDefName,
                    CategoryId = flowDef.CategoryId,
                    BusinessUrl = flowDef.BusinessUrl,
                    AuditUrl = flowDef.AuditUrl,
                    CreateDate = DateTime.Now

                };

                context.WorkFlowDefs.Add(data);
                context.SaveChanges();
            }
            return flowDef.Id;
        }

        public FlowMessage UpdateFlowDef(Models.WorkFlowDefinition model)
        {
            FlowMessage flowMessage = new FlowMessage();
            try
            {
                using (var context = new WorkFlowDbContext())
                {
                    var def = context.WorkFlowDefs.Find(model.Id);
                    if (def == null)
                    {
                        throw new Exception("找不到要修改的对象");
                    }
                    else
                    {
                        def.WorkFlowDefName = model.FlowDefName;
                        def.WorkFlowDefKey = model.FlowDefKey;
                        def.CategoryId = model.CategoryId;
                        def.BusinessUrl = model.BusinessUrl;
                        def.AuditUrl = model.AuditUrl;
                        context.WorkFlowDefs.AddOrUpdate(def);
                        context.SaveChanges();
                    }
                }
            }
            catch (Exception ex)
            {
                flowMessage.Code = CodeEum.Fail;
                flowMessage.Message = ex.Message;
            }
            return flowMessage;
        }

        public FlowMessage DeleteFlowDef(IList<string> ids)
        {
            FlowMessage flowMessage = new FlowMessage();
            try
            {
                using (var context = new WorkFlowDbContext())
                {


                    var flowdefs = context.WorkFlowDefs.Where(c => ids.Contains(c.Id));
                    WorkFlowInstance instance = context.WorkFlowInstances.FirstOrDefault(x => ids.Contains(x.WorkFlowDefId) && x.RunStatus != FlowRunStatus.History);

                    if (instance != null)
                    {
                        throw new Exception($"{instance.WorkFlowDef.WorkFlowDefName}存在未完成的流程数据，不能删除");
                    }

                    flowdefs.ForEach(c =>
                    {

                        c.IsDelete = true;
                    });

                    context.SaveChanges();
                }
            }
            catch (Exception ex)
            {
                flowMessage.Code = CodeEum.Fail;
                flowMessage.Message = ex.Message;
            }
            return flowMessage;
        }

        public WorkFlowDefinition GetFlowDef(string id)
        {
            Models.WorkFlowDefinition model = new Models.WorkFlowDefinition();

            using (var context = new WorkFlowDbContext())
            {
                var data = context.WorkFlowDefs.Find(id);

                if (data != null)
                {
                    model.Id = data.Id;
                    model.FlowDefKey = data.WorkFlowDefKey;
                    model.FlowDefName = data.WorkFlowDefName;
                    model.CategoryId = data.CategoryId;
                    model.AuditUrl = data.AuditUrl;
                    model.BusinessUrl = data.BusinessUrl;
                    if (data.WorkFlowCategory != null)
                    {
                        model.CategoryName = data.WorkFlowCategory.CategoryName;
                    }

                }

            }
            return model;
        }

        /// <summary>
        /// 得到定义的流程
        /// </summary>
        /// <param name="flowDefId"></param>
        /// <returns></returns>
        public WorkFlowModel GetFlowModel(string flowDefId)
        {
            WorkFlowModel flowDef = new WorkFlowModel();
            using (var context = new WorkFlowDbContext())
            {
                var data = context.WorkFlowDefs.Find(flowDefId);
                if (data == null)
                {
                    throw new Exception("找不到流程定义");
                }
                var version = context.WorkFlowVersions.OrderByDescending(c => c.VersionNumber).FirstOrDefault(x => x.WorkFlowDefId == flowDefId);

                if (version != null && !String.IsNullOrEmpty(version.WorkFlowDocument))
                {
                    WorkFlowDocument document = XmlSerializeUtil.Deserialize(typeof(WorkFlowDocument), version.WorkFlowDocument) as WorkFlowDocument;

                    flowDef.Id = data.Id;
                    flowDef.WorkFlowDefKey = data.WorkFlowDefKey;
                    flowDef.WorkFlowDefName = data.WorkFlowDefName;
                    flowDef.CategoryId = data.CategoryId;
                    if (data.WorkFlowCategory != null)
                    {
                        flowDef.CategoryName = data.WorkFlowCategory.CategoryName;

                    }
                    flowDef.CreateDate = data.CreateDate;
                    if (document != null)
                    {
                        flowDef.NodeLinks = document.NodeLinks;
                        flowDef.Nodes = document.Nodes;
                    }
                   
                }
                else
                {
                    flowDef = new WorkFlowModel();

                    flowDef.Id = data.Id;
                    flowDef.WorkFlowDefKey = data.WorkFlowDefKey;
                    flowDef.WorkFlowDefName = data.WorkFlowDefName;
                    flowDef.CreateDate = data.CreateDate;
                    flowDef.CategoryId = data.CategoryId;
                    if (data.WorkFlowCategory != null)
                    {
                        flowDef.CategoryName = data.WorkFlowCategory.CategoryName;
                    }


                }



            }
            return flowDef;
        }




        /// <summary>
        /// 保存流程设置
        /// </summary>
        /// <param name="flowDef"></param>
        /// <returns></returns>
        public FlowMessage SaveDiagram(WorkFlowModel flowDef)
        {

            FlowMessage messageInstanse = new FlowMessage();

            try
            {
                WorkFlowModel oldFlowModel = GetFlowModel(flowDef.Id);


                if (flowDef.Nodes == null || flowDef.Nodes.Count == 0)
                {

                    throw new Exception("节点不能为空");
                }

                int startNodeCount = flowDef.Nodes.Count(c => c.NodeType == NodeType.Start);
                if (startNodeCount != 1)
                {

                    throw new Exception("必须有一个开始节点，开始节点只能有一个");
                }

                int taskNodeCount = flowDef.Nodes.Count(c => c.NodeType == NodeType.Task);
                if (taskNodeCount == 0)
                {

                    throw new Exception("至少有一个任务节点");
                }


                int endNodeCount = flowDef.Nodes.Count(c => c.NodeType == NodeType.End);

                if (endNodeCount != 1)
                {

                    throw new Exception("必须有一个结束节点，结束节点只能有一个");
                }

                foreach (var oNode in oldFlowModel.Nodes)
                {
                    bool flag = true;
                    foreach (var newNode in flowDef.Nodes)
                    {
                        if (oNode.Id.Equals(newNode.Id))
                        {
                            flag = false;
                        }
                    }
                    if (flag)
                    {
                        messageInstanse.Code = CodeEum.Fail;
                        messageInstanse.Message = string.Format("任务【{0}】已被删除，保存后可能会导致已有数据出错，请保存新版本", oNode.NodeDefName);
                        return messageInstanse;
                    }
                }

                using (var context = new WorkFlowDbContext())
                {

                    string model = GetWorkFlowDocument(flowDef);

                    WorkFlowVersion flowFlowVersion = context.WorkFlowVersions.OrderByDescending(c => c.VersionNumber).FirstOrDefault(c => c.WorkFlowDefId == flowDef.Id);
                    if (flowFlowVersion != null)
                    {
                        flowFlowVersion.WorkFlowDocument = model;
                        context.WorkFlowVersions.AddOrUpdate(flowFlowVersion);
                    }
                    else
                    {
                        flowFlowVersion = new WorkFlowVersion();
                        flowFlowVersion.Id = Guid.NewGuid().ToString().ToUpper();
                        flowFlowVersion.WorkFlowDefId = flowDef.Id;
                        flowFlowVersion.WorkFlowDocument = model;
                        flowFlowVersion.CreateDate = DateTime.Now;
                        flowFlowVersion.Remark = flowDef.Remark;
                        int currentVersion = 1;
                        flowFlowVersion.VersionNumber = currentVersion;
                        context.WorkFlowVersions.Add(flowFlowVersion);
                    }
                    context.SaveChanges();

                }

            }
            catch (Exception ex)
            {

                messageInstanse.Code = CodeEum.Fail;
                messageInstanse.Message = ex.Message;
            }



            return messageInstanse;

        }

        private string GetWorkFlowDocument(WorkFlowModel flowDef)
        {
            WorkFlowDocument document = new WorkFlowDocument();
            
            document.Nodes = flowDef.Nodes;
            document.NodeLinks = flowDef.NodeLinks;

            string xml = XmlSerializeUtil.Serializer(typeof(WorkFlowDocument), document);
            return xml;
        }


        /// <summary>
        /// 保存流程设置
        /// </summary>
        /// <param name="flowDef"></param>
        /// <returns></returns>
        public FlowMessage SaveDiagramWithNewVersion(WorkFlowModel flowDef)
        {

            FlowMessage messageInstanse = new FlowMessage();

            try
            {

                if (flowDef.Nodes == null || flowDef.Nodes.Count == 0)
                {

                    throw new Exception("节点不能为空");
                }

                int startNodeCount = flowDef.Nodes.Count(c => c.NodeType == NodeType.Start);
                if (startNodeCount != 1)
                {

                    throw new Exception("必须有一个开始节点，开始节点只能有一个");
                }

                int taskNodeCount = flowDef.Nodes.Count(c => c.NodeType == NodeType.Task);
                if (taskNodeCount == 0)
                {

                    throw new Exception("至少有一个任务节点");
                }


                int endNodeCount = flowDef.Nodes.Count(c => c.NodeType == NodeType.End);

                if (endNodeCount != 1)
                {

                    throw new Exception("必须有一个结束节点，结束节点只能有一个");
                }


                using (var context = new WorkFlowDbContext())
                {

                    string model = GetWorkFlowDocument(flowDef);

                    WorkFlowVersion flowFlowVersion = new WorkFlowVersion();
                    flowFlowVersion.Id = Guid.NewGuid().ToString().ToUpper();
                    flowFlowVersion.WorkFlowDefId = flowDef.Id;
                    flowFlowVersion.WorkFlowDocument = model;
                    flowFlowVersion.CreateDate = DateTime.Now;
                    flowFlowVersion.Remark = flowDef.Remark;
                    int currentVersion = 1;
                    var max = context.WorkFlowVersions.Count(c => c.WorkFlowDefId == flowDef.Id);
                    currentVersion += max;

                    flowFlowVersion.VersionNumber = currentVersion;
                    context.WorkFlowVersions.Add(flowFlowVersion);
                    context.SaveChanges();
                }

            }
            catch (Exception ex)
            {

                messageInstanse.Code = CodeEum.Fail;
                messageInstanse.Message = ex.Message;
            }



            return messageInstanse;

        }
        /// <summary>
        /// 返回流程图
        /// </summary>
        /// <param name="flowDefId"></param>
        /// <returns></returns>
        public Bitmap GetBitmap(string flowDefId)
        {
            Bitmap bitmap = null;
            using (var context = new WorkFlowDbContext())
            {
                var model = GetFlowModel(flowDefId);
                var nodes = model.Nodes.Where(c => c.FlowDefId == flowDefId).ToList();
                var nodelinks = model.NodeLinks.Where(c => c.FlowDefId == flowDefId).ToList();
                bitmap = new DrawingCurve().DrawingFlow(nodes, nodelinks);
            }
            return bitmap;
        }

        //private FlowModel GetCurrentVersionFlow(string flowDefId, int? flowVersion = null)
        //{

        //    using (var context = new WorkFlowDbContext())
        //    {
        //        WorkFlowVersion version;
        //        if (flowVersion.HasValue)
        //        {
        //            version = context.WorkFlowVersions.OrderByDescending(c => c.FlowVersion).FirstOrDefault(x => x.FlowDefId == flowDefId && x.FlowVersion == flowVersion.Value);
        //        }
        //        else
        //        {
        //            version = context.WorkFlowVersions.OrderByDescending(c => c.FlowVersion).FirstOrDefault(x => x.FlowDefId == flowDefId);
        //        }


        //        if (version != null && !String.IsNullOrEmpty(version.FlowModel))
        //        {
        //            FlowModel flowDef = XmlSerializeUtil.Deserialize(typeof(FlowModel), version.FlowModel) as FlowModel;

        //            if (flowDef != null)
        //            {
        //                return flowDef;
        //            }
        //        }
        //    }
        //    return null;
        //}

        public PagedResult<WorkFlowModel> GetList(FlowDefFilter filters)
        {
            using (var context = new WorkFlowDbContext())
            {

                var query = context.WorkFlowDefs.Where(x => x.IsDelete == false);
                if (!String.IsNullOrEmpty(filters.keywords))
                {
                    query = query.Where(c => c.WorkFlowDefName.Contains(filters.keywords));
                }
                return query.OrderByCustom(filters.sidx, filters.sord)
                    .Select(item => new WorkFlowModel
                    {
                        Id = item.Id,
                        WorkFlowDefKey = item.WorkFlowDefKey,
                        WorkFlowDefName = item.WorkFlowDefName,
                        CategoryId = item.CategoryId,
                        CategoryName = item.WorkFlowCategory.CategoryName,
                        CreateDate = item.CreateDate
                    }).Paging(filters.page, filters.rows);
            }
        }
    }
}
